package com.googlecode.archimedes.filegen.generator.velocity;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;

import com.googlecode.archimedes.filegen.controller.GenerationException;
import com.googlecode.archimedes.filegen.generator.AbstractGenerator;
import com.googlecode.archimedes.filegen.template.Template;

/**
 * Document me! 
 * 
 * @author Erik Gustavson
 * @version $Id: VelocityGenerator.java 51 2003-11-28 18:23:31 +0000 (Fri, 28 Nov 2003) erik $
 *
 * Created on Oct 30, 2003
 */
public class VelocityGenerator {

	private static Log logger = LogFactory.getLog(VelocityGenerator.class);
	
	/**
	 * Document me!
	 * 
	 * 
	 */
	private VelocityGenerator() {
		super();
	}

	//----- Main Methods -----------------------------------------------------------

	protected static void generate(AbstractGenerator generator, String prefix, Template template, VelocityContext context) throws GenerationException {
		try {
			//setup velocity
			Velocity.init(getProperties(generator));

			String vmTemplateName = template.getTemplateName() + ".vm";
			String outputPath = generator.getOutputDirectoy() + template.getOutputPath();
			
			String outputFileName = prefix + template.getTemplateName() + template.getExtension();

			org.apache.velocity.Template velocityTemplate = Velocity.getTemplate(vmTemplateName);
			Writer writer = getWriter(outputPath, outputFileName);
			logger.debug("Using a template [" + vmTemplateName + "]");
			velocityTemplate.merge(context, writer);
			
			tearDown(writer);

		} catch (ResourceNotFoundException e) {
			logger.error("VelocityTemplate : error : cannot find template [" + template.getTemplateName() + "]", e);
			throw new GenerationException(e);
		} catch (ParseErrorException e) {
			logger.error("VelocityTemplate : Syntax error in template [" + template.getTemplateName() + "]", e);
			throw new GenerationException(e);
		} catch (IOException e) {
			logger.error("VelocityTemplate : Syntax error closing template [" + template.getTemplateName() + "]", e);
			throw new GenerationException(e);
		} catch (Exception e) {
			throw new GenerationException(e);
		}
	}

	/**
	 * 
	 * Document me!
	 * 
	 * @TODO The whole outputpath/writer thing is killing me.
	 * @TODO this is not an elegant solution at all.
	 *   
	 * @throws GenerationException If there was a problem closing out the resources.
	 */
	protected static void tearDown(Writer writer) throws GenerationException {
		try {
			writer.flush();
			writer.close();
			
		} catch (IOException e) {
			logger.error("There was a problem closing out the writer", e);
			throw new GenerationException(e);
		}
	}

	//----- Utility Methods -----------------------------------------------------------

	/**
	 * Returns the properties necessary for running Velocity.
	 * 
	 * @see com.tps.filegen.template.Generateable#getProperties()
	 */
	protected static Properties getProperties(AbstractGenerator generator) {
		//@TODO load these bad boys from the Velocity Poppertieds file
		Properties p = new Properties();

		p.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, generator.getResourceDirectory() + ", " + generator.getIncludeDirectory());
		p.setProperty("runtime.log.logsystem.log4j.category", VelocityGenerator.class.getName());

		p.setProperty(RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, "true");
		p.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");

		return p;
	}

	protected static Writer getWriter(String path, String fileName) throws GenerationException {
		//@TODO The thought here is that you could set the Writer type in the properties file
		try {
			logger.debug("Generating file [" + path + fileName + "].");
			File file = new File(path, fileName);
			buildTree(file);
			return new FileWriter(file);
			
		} catch (IOException e) {
			logger.error("There was a problem creating the file [" + path + fileName + "].", e);
			throw new GenerationException(e);
		}
	}

	protected static void buildTree(File file) {
		//find the parent of the file in question
		File parent = file.getParentFile();

		//create the parent & any directories needed
		parent.mkdirs();
	}
}
